import time
from datetime import datetime,timedelta


from flask import render_template, request, current_app, redirect, url_for, session, g, jsonify, abort

from info import constants, db
from info.models import User, News, Category
from info.modules.admin import admin_blu
from info.utils.common import set_func
from info.utils.image_storage import storage
from info.utils.response_code import RET



@admin_blu.route('/news_type', methods=['POST', 'GET'])
def news_type():
    """
    新闻分类管理界面
    :return:
    """
    if request.method == 'GET':
        # 查新新闻分类模型对象
        categories_model = Category.query.all()

        categories = []
        for category in categories_model:
            categories.append(category.to_dict())

        # 移除最新
        categories.pop(0)

        data = {
            'categories': categories
        }

        return render_template('admin/news_type.html', data=data)

    # 获取要添加的分类名称
    category_name = request.json.get('name')
    category_id = request.json.get('id')
    if not category_name:
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    if  category_id: # 如果有传过来id,说明是修改分类名称
        try:
            category = Category.query.get(category_id)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='数据查询错误')

        if not category:
            return jsonify(errno=RET.NODATA, errmsg='分类不存在')

        category.name = category_name
    else:
        # 说明是添加属性
        category = Category()
        category.name = category_name
        db.session.add(category)

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据保存失败')

    return jsonify(errno=RET.OK, errmsg='OK')


@admin_blu.route('/edit_detail', methods=['POST', 'GET'])
def edit_detail():
    """"""
    # 新闻版式编辑界面详情
    if request.method == 'GET':
        # 1.获取新闻id
        news_id = request.args.get('news_id')

        # 判断传过来新闻id是否为整数
        try:
            news_id = int(news_id)
        except Exception as e:
            current_app.logger.error(e)
            return render_template('admin/news_edit_detail.html', errmsg='参数错误')

        # 根据新闻id获取新闻
        try:
            news = News.query.get(news_id)
        except Exception as e:
            current_app.logger.error(e)
            return render_template('admin/news_edit_detail.html', errmsg='数据查询失败')

        if not news:
            return render_template('admin/news_edit_detail.html', errmsg='新闻不存在')

        categories = []
        # 查询所有分类
        categories_model = Category.query.all()

        for category in categories_model:
            c_dict = category.to_dict()
            c_dict['is_selected'] = False
            # 如果新闻的分类id　== 分类id
            if news.category_id == category.id:
                c_dict['is_selected'] = True
            categories.append(c_dict)

        # 移除最新
        categories.pop(0)

        data = {
            'news': news.to_dict(),
            'categories': categories
        }

        return render_template('admin/news_edit_detail.html', data=data)

    # 如果是POST,是对版式进行编辑

    # 1.获取参数
    title = request.form.get('title')  # 新闻标题
    category_id = request.form.get('category_id')  # 新闻分类
    digest = request.form.get('digest')  # 新闻摘要
    index_image = request.files.get('index_image')
    content = request.form.get('content')  # 新闻内容
    news_id = request.form.get('news_id')  # 新闻id


    # 判断参数
    if not all([title, category_id, digest, content, news_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 校验新闻id
    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 尝试读取图片
    try:
        index_image = index_image.read()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')


    # 根据新闻id查出对应的新闻模型
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询失败')

    if not news:
        return jsonify(errno=RET.NODATA, errmsg='数据不存在')

    # 把新闻图片上传到七牛
    try:
        key = storage(index_image)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='上传图片失败')

    # 修改新闻模型
    news.title = title
    news.category_id = category_id
    news.content = content
    news.digest = digest
    news.index_image_url = constants.QINIU_DOMIN_PREFIX + key

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DATAERR, errmsg='数据保存失败')

    return jsonify(errno=RET.OK, errmsg='OK')


@admin_blu.route('/edit')
def edit():
    """
    新闻版式编辑界面数据展示
    :return:
    """
    # 1.接收参数
    p = request.args.get('p', 1)
    keyword = request.args.get('keyword')

    # 2.校验参数
    try:
        p = int(p)
    except Exception as e:
        current_app.logger.error(e)
        p = 1

    # 设置默认参数
    news_list = []
    # 当前页数
    current_page = 0
    # 总页数
    total_page = 0
    filters = []
    if  keyword:
        filters.append(News.title.contains(keyword))

    # 3.业务逻辑处理,从数据库中查询新闻
    try:
        paginate = News.query.filter(*filters).paginate(p, constants.ADMIN_NEWS_PAGE_MAX_COUNT, False)
        # 获取查询出来的数据
        news_list = paginate.items
        # 获取当前页数
        current_page = paginate.page
        # 获取总页数
        total_page = paginate.pages
    except Exception as e:
        current_app.logger.error(e)

    news_dict_li = []
    # 遍历列表对象转换成字典对象
    for new in news_list:
        news_dict_li.append(new.to_review_dict())

    data = {
        'news': news_dict_li,
        'total_page': total_page,
        'current_page': current_page
    }

    return render_template('admin/news_edit.html', data=data)


@admin_blu.route('/review_detail', methods=['POST', 'GET'])
def news_review_detail():
    """
    审核新闻详情
    :return:
    """
    # 如果是get请求，就是获取审核新闻详情页面
    if request.method == 'GET':

        # 1.获取新闻id
        news_id = request.args.get('news_id')

        # 2.校验新闻id
        try:
            news_id = int(news_id)
        except Exception as e:
            current_app.logger.error(e)


        # 3.根据新闻id去查询新闻
        try:
            news = News.query.get(news_id)
        except Exception as e:
            current_app.logger.error(e)

        if not news:
            return render_template('admin/news_review_detail.html', errmsg='未查询到此新闻')

        data = {
            'news': news.to_dict()
        }

        return render_template('admin/news_review_detail.html', data=data)


    # 代码走到这里,就是POST请求，就是来对新闻执行审核的具体操作

    # 1.获取参数，news_id 新闻id 　action 的值为　"accept", "reject" accept　审核通过　reject 拒绝通过
    news_id = request.json.get('news_id')
    action = request.json.get('action')

    # 2.校验参数
    if not all([news_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    try:
        news_id = int(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    if action not in ('accept', 'reject'):
        return jsonify(errno=RET.PARAMERR, errmsg='参数错误')

    # 3.业务逻辑处理
    # 根据新闻id去查询具体的新闻模型对象
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据查询失败')

    if not news:
        return jsonify(errno=RET.NODATA, errmsg='新闻不存在')

    if action == 'accept':  # 表示审核通过,就把新闻的状态改为0
        news.status = 0
    else:
        # 表示新闻审核未通过
        # 需要获取未通过原因
        reason = request.json.get('reason')
        news.status = -1  # 表示审核未通过
        news.reason = reason  # 审核未通过的原因

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='数据保存失败')

    return jsonify(errno=RET.OK, errmsg='OK')



@admin_blu.route('/review')
def news_review():
    """
    新闻审核
    :return:
    """
    # 如果是GET请求只是获取新闻审核界面
    # 1.获取页数
    p = request.args.get('p', 1)
    # 获取搜索关键字
    keyword = request.args.get('keyword')



    # 2.校验参数
    try:
        p = int(p)
    except Exception as e:
        current_app.logger.error(e)

    # 设置默认值
    news_list = []
    current_page = 0
    total_page = 0

    filters = [News.status!=0]

    if keyword:
        # contains包含
        filters.append(News.title.contains(keyword))
    # 3.业务逻辑处理，查询数据
    try:
        paginate = News.query.filter(*filters).paginate(p, constants.ADMIN_USER_PAGE_MAX_COUNT, False)
    except Exception as e:
        current_app.logger.error(e)

    # 获取查询出来的数据
    news_list = paginate.items
    # 当前页数
    current_page = paginate.page
    # 总页数
    total_page = paginate.pages

    news_dict_li = list()

    for new in news_list:
        news_dict_li.append(new.to_review_dict())

    data={
        'news': news_dict_li,
        'current_page': current_page,
        'total_page': total_page
    }

    return render_template('admin/news_review.html', data=data)


@admin_blu.route('/list')
def user_list():
    """
    注册用户列表显示
    因为是显示数据所以是get请求
    :return:
    """
    # 1．获取参数
    page = request.args.get('p' ,1)  # 当前页数

    # 2.校验参数
    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        p = 1

    # 设置默认值
    users_list = []
    current_page = 0
    total_page = 0


    try:
        paginate = User.query.order_by(User.create_time.desc()).paginate(page, constants.OTHER_NEWS_PAGE_MAX_COUNT, False)
        # 查出数据
        users_list = paginate.items
        # 查出当前页数
        current_page = paginate.page
        # 查出总页数
        total_page = paginate.pages
    except Exception as e:
        current_app.logger.error(e)

    users_dict_list = []
    for users in users_list:
        users_dict_list.append(users.to_admin_dict())


    data={
        'users': users_dict_list,
        'current_page': current_page,
        'total_page': total_page
    }

    return render_template('admin/user_list.html', data=data)


@admin_blu.route('/count')
def count():
    """
    用户人数统计
    :return:
    strptime: 将一个时间字符串解析成一个时间对象
    """

    # 1.查询用户总数,非管理员

    # 日新增人数
    total_count = 0
    try:
        total_count = User.query.filter(User.is_admin==False).count()
    except Exception as e:
        current_app.logger.error(e)


    # 月增加人数
    month_count = 1
    # 月增加人数,就是从这个月的1月1号到今天增加的人数
    # 1.第一步:获取今天的时间
    t = time.localtime() # 获取现在的时间
    # 格式　begin_month_date = datetime.strptime('2018-10-28', '%Y-%m-%d')
    begin_month_date = datetime.strptime(('%d-%02d-01' % (t.tm_year, t.tm_mon)), '%Y-%m-%d')

    try:
        month_count = User.query.filter(User.create_time > begin_month_date, User.is_admin==False).count()
    except Exception as e:
        current_app.logger.error(e)


    # 日新增人数
    day_count = 0
    # 日增加人数,就是注册时间在今天的０点０分之后的人
    begin_day_date = datetime.strptime(('%d-%02d-%02d' % (t.tm_year, t.tm_mon, t.tm_mday)), '%Y-%m-%d')
    try:
        day_count = User.query.filter(User.create_time > begin_day_date, User.is_admin==False).count()
    except Exception as e:
        current_app.logger.error(e)


    # TODO 折线图数据，查询每天用户的活跃度,就是查看这一天的时间有多少个用户登录了

    # 定义一个列表 ,存放活跃的时间
    active_time = []
    # 存放活跃的人数
    active_count = []

    # 分析：取到当前的时间-1-2-3-4 就是取到前面的天数

    begin_day_date = datetime.strptime(('%d-%02d-%02d' % (t.tm_year, t.tm_mon, t.tm_mday)), '%Y-%m-%d')
    for i in range(0, 31):
        #　取到今天的２４点
        begin_date = begin_day_date-timedelta(days=i)
        # 取到明天的０点０时
        end_date = begin_day_date-timedelta(days=i-1)
        # 查询当天的活跃度
        # User.query.filter(User.is_admin == False, User.last_login >= 今天的０点０时０分０秒, User.last_login < 今天的２４点)
        count = User.query.filter(User.is_admin==False, User.last_login>=begin_date, User.last_login<end_date).count()
        active_count.append(count)
        active_time.append(begin_date.strftime('%Y-%m-%d'))


    # 翻转列表，把最晚的日期放在最后面
    active_count.reverse()
    # 翻转列表，把活跃度和日期时间对应
    active_time.reverse()

    data = {
        'total_count': total_count,
        'month_count': month_count,
        'day_count': day_count,
        'active_time': active_time,
        'active_count': active_count

    }

    return render_template('admin/user_count.html', data=data)


@admin_blu.route('/index')
@set_func
def index():
    """
    后台新闻首页
    :return:
    """
    user = g.user
    data = {
        'user_info': user.to_admin_dict()
    }

    return render_template('admin/index.html', data=data)


@admin_blu.route('/login', methods=['POST', 'GET'])
def login():
    """
    后台的登录页面
    :return:
    """
    # 如果是get请求,把这个界面返回过去
    if request.method == 'GET':
        user_id = session.get('user_id',None)
        is_admin = session.get('is_admin', False)
        if user_id and is_admin: # 如果这个管理员已经登录,直接重定向到后台首页
            return redirect(url_for('admin.index'))
        return render_template('admin/login.html')

    #　如果是post请求，发起登录请求
    # 1,获取两个参数,账号和密码
    user_name = request.form.get('username')
    password = request.form.get('password')

    # 2.校验参数
    if not all([user_name, password]):
        return render_template('admin/login.html', errmsg='参数错误')

    # 3.业务逻辑处理
    try:
        user = User.query.filter(User.mobile == user_name).first()
    except Exception as e:
        current_app.logger.error(e)
        return render_template('admin/login.html', errmsg='参数错误')

    if not user:
        return render_template('admin/login.html', errmsg='用户不存在')

    if not user.check_passowrd(password):
        return render_template('admin/login.html', errmsg='用户名或者密码')

    if not user.is_admin:
        return render_template('admin/login.html', errmsg='用户权限错误')


    # 保持用的登录状态
    session['user_id'] = user.id
    session['user_nick_name'] = user.nick_name
    session['user_mobile'] = user.mobile
    session['is_admin'] = True

    return redirect(url_for('admin.index'))